﻿
#region Using Statements

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

#endregion


namespace Freeform
{

    #region Actor

    /// <summary>
    /// Actors are used to graphically represent a body through a viewport.
    /// </summary>
    public class Actor
    {

        #region Members

        /// <summary>
        /// Gets the entity that this actor represents.
        /// </summary>
        public virtual Entity Entity { get; private set; }


        /// <summary>
        /// Gets or sets the colour overlay of the actor.
        /// </summary>
        public virtual Color ColourOverlay { get; set; }


        /// <summary>
        /// Gets or sets the depth of the actor. (0 - front of viewport, 1 - back of viewport.)
        /// </summary>
        public virtual Single Depth { get; set; }


        /// <summary>
        /// Gets or sets whether this actor is currently visible.
        /// </summary>
        public virtual Boolean Visible { get; set; }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new Actor.
        /// </summary>
        /// <param name="entity">The entity that this actor will represent.</param>
        public Actor(Entity entity) 
        {
            Entity = entity;
            ColourOverlay = Color.White;
            Visible = true;
            Depth = 0.5f;
            Entity.Actor = this;
        }

        #endregion
        

        #region Draw

        /// <summary>
        /// Draws the entity onto the viewport.
        /// </summary>
        /// <param name="spatial">The spatial properties of the body.</param>
        /// <param name="viewport">The viewport onto which the entity is being rendered.</param>
        /// <param name="time">Provides a snapshot of timing values.</param>
        public virtual void Draw(Viewport2D viewport, GameTime time) { }

        #endregion

    }

    #endregion


    #region Actor_Image2D

    /// <summary>
    /// Actors are used to graphically represent an entity on a viewport.
    /// </summary>
    public class Actor_Image2D : Actor
    {

        #region Members

        /// <summary>
        /// Gets a reference to the animation set for this actor.
        /// </summary>
        public virtual AnimationSet Animations { get; private set; }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new 2d image actor.
        /// </summary>
        /// <param name="entity">The entity that this actor represents.</param>
        public Actor_Image2D(Entity entity)
            : base(entity)
        {
            Animations = new AnimationSet();
        }


        /// <summary>
        /// Creates a new 2d image actor.
        /// </summary>
        /// <param name="entity">The entity that this actor represents.</param>
        /// <param name="animations">The animation set for the actor.</param>
        public Actor_Image2D(Entity entity, AnimationSet animations)
            : base(entity)
        {
            Animations = animations;
        }

        #endregion


        #region Draw

        /// <summary>
        /// Draws the entity onto the viewport.
        /// </summary>
        /// <param name="spatial">The spatial properties of the actor in world coordinates.</param>
        /// <param name="viewport">The viewport onto which the entity is being rendered.</param>
        /// <param name="time">Provides a snapshot of timing values.</param>
        public override void Draw(Viewport2D viewport, GameTime time)
        {
            // Check early breaks.
            if (viewport.SpriteBatch == null) return;
            if (Animations.Current == null) return;
            if (Entity == null) return;

            // Calculate drawing data.
            Animation Draw_Animation = Animations.Current;
            Vector2 Draw_Position = viewport.Camera.TransformPosition(Entity.SpatialProperties.Position);
            Vector2 Draw_Size = viewport.Camera.TransformSize(Entity.SpatialProperties.Size);
            Vector2 Draw_Origin = new Vector2(Draw_Animation.WidthPerCell / 2, Draw_Animation.HeightPerCell / 2);
            Rectangle Draw_Destination = new Rectangle((int)Draw_Position.X, (int)Draw_Position.Y, (int)Draw_Size.X, (int)Draw_Size.Y);
            Rectangle Draw_Source = Draw_Animation.UpdateSource(time);

            // Draw entity.
            viewport.SpriteBatch.Draw(Draw_Animation.Texture, Draw_Destination, Draw_Source, ColourOverlay, Entity.SpatialProperties.Direction, Draw_Origin, SpriteEffects.None, Depth);
        }

        #endregion

    }

    #endregion


    #region Actor_Text2D

    /// <summary>
    /// An actor that renders itself as a text line.
    /// </summary>
    public class Actor_Text2D : Actor
    {

        #region Members

        /// <summary>
        /// Gets or sets the text for this actor.
        /// </summary>
        public virtual String Text { get; set; }


        /// <summary>
        /// Gets or sets the spritefont of this actor.
        /// </summary>
        public virtual SpriteFont Font { get; set; }


        /// <summary>
        /// Gets or sets whether the actor should use the natural font size to draw.
        /// If true the font size will be scaled by the Entity's NaturalFontScaling value (use Vector2.One for the natural font size.)
        /// Otherwise the size of the font will be resized to be exactly equal to the Entity's size value.
        /// </summary>
        public virtual Boolean UseNaturalFontSize { get; set; }


        /// <summary>
        /// Gets or sets the value to scale the natural font size by if the actor is using the natural font size.
        /// </summary>
        public virtual Vector2 NaturalFontScaling { get; set; }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new 2d text actor.
        /// </summary>
        /// <param name="entity">The entity that this actor represents.</param>
        public Actor_Text2D(Entity entity)
            : base(entity)
        {
            Text = "";
            Font = null;
            NaturalFontScaling = Vector2.One;
        }


        /// <summary>
        /// Creates a new 2d text actor.
        /// </summary>
        /// <param name="entity">The entity that this actor represents.</param>
        /// <param name="text">The text of the actor.</param>
        /// <param name="font">The font of the actor.</param>
        public Actor_Text2D(Entity entity, String text, SpriteFont font)
            : base(entity)
        {
            Text = text;
            Font = font;
            NaturalFontScaling = Vector2.One;
        }

        #endregion


        #region Draw

        /// <summary>
        /// Draws the entity onto the viewport.
        /// </summary>
        /// <param name="spatial">The spatial properties of the actor in world coordinates.</param>
        /// <param name="viewport">The viewport onto which the entity is being rendered.</param>
        /// <param name="time">Provides a snapshot of timing values.</param>
        public override void Draw(Viewport2D viewport, GameTime time)
        {
            // Check early breaks.
            if (viewport.SpriteBatch == null) return;
            if (Font == null) return;
            if (Text == null) return;
            if (Entity == null) return;

            Vector2 Draw_Position = viewport.Camera.TransformPosition(Entity.SpatialProperties.Position);
            Vector2 Draw_Measure = Font.MeasureString(Text);
            Vector2 Draw_Origin = Draw_Measure / 2;

            // If we're using natural font size we need to adjust the size of the entity.
            if (UseNaturalFontSize)
                Entity.SpatialProperties.Size = Draw_Measure * NaturalFontScaling;

            Vector2 Draw_Size = viewport.Camera.TransformSize(Entity.SpatialProperties.Size);
            Vector2 Draw_Scale = Draw_Size / Draw_Measure;

            viewport.SpriteBatch.DrawString(Font, Text, Draw_Position, ColourOverlay, Entity.SpatialProperties.Direction, Draw_Origin, Draw_Scale, SpriteEffects.None, Depth);
        }

        #endregion

    }

    #endregion

}
